﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows;

namespace WpfApplication17
{
    class Helper
    {
        public static DashStyle CreateDashStyle(string str)
        {
            DashStyle dashStyle = new DashStyle();
            dashStyle.Dashes = (DoubleCollection)new DoubleCollectionConverter().ConvertFromString(str);
            return dashStyle;
        }

        public static Pen CreatePen(Brush brush, DashStyle ds, double thickness = 1)
        {
            Pen pen = new Pen() { Brush = brush, Thickness = thickness, DashStyle = ds };
            return pen;
        }

        public static PointCollection ConcatReversePoints(PointCollection first, PointCollection needReverse)
        {
            return new PointCollection(first.Concat(needReverse.Reverse()));
        }

        public static List<PointCollection> GetOffsetPoints(PointCollection points, double offset, Point crosspoint, int isOffset = -1)
        {
            List<PointCollection> listpointstr = new List<PointCollection>();
            PointCollection linepoints = points;
            double buffer = offset;
            PointCollection pc = new PointCollection();
            PointCollection pc2 = new PointCollection();

            for (int i = 0; i < linepoints.Count; i++)
            {
                if (i < linepoints.Count - 1)
                {
                    Point RecEndpoint = new Point(linepoints[i + 1].X, linepoints[i + 1].Y);
                    Point RecStartpoint = new Point(linepoints[i].X, linepoints[i].Y);
                    Vector vec = new Vector(RecStartpoint.X - RecEndpoint.X, RecStartpoint.Y - RecEndpoint.Y);
                    vec.Normalize();

                    Vector normalVector = new Vector(vec.Y, -vec.X);


                    switch (isOffset)
                    {

                        case -1: break;
                        case 0:
                            if (i == 0)
                            {
                                RecStartpoint = RecStartpoint - vec * 90;// *90;
                            }
                            break;
                        case 1:
                            if (i == linepoints.Count - 2)
                            {
                                RecEndpoint = RecEndpoint + vec * 60;
                            }
                            break;
                        default:
                            break;
                    }

                    //路基path1
                    pc.Add(new Point(RecStartpoint.X + normalVector.X * buffer, RecStartpoint.Y + normalVector.Y * buffer));
                    pc.Add(new Point(RecEndpoint.X + normalVector.X * buffer, RecEndpoint.Y + normalVector.Y * buffer));

                    normalVector = new Vector(-vec.Y, vec.X);

                    //路基path2
                    pc2.Add(new Point(RecStartpoint.X + normalVector.X * buffer, RecStartpoint.Y + normalVector.Y * buffer));
                    pc2.Add(new Point(RecEndpoint.X + normalVector.X * buffer, RecEndpoint.Y + normalVector.Y * buffer));
                }
            }
            pc = UpdatePoints(pc);
            pc2 = UpdatePoints(pc2);
            listpointstr.Add(pc);
            listpointstr.Add(pc2);
            return listpointstr;
        }


        public static PointCollection DrawRoadline(List<PointCollection> pl, int lanenumber, int laneindex)
        {
            PointCollection line = new PointCollection();

            for (int i = 0; i < pl[0].Count; i++)
            {
                Vector vec = new Vector(pl[0][i].X - pl[1][i].X, pl[0][i].Y - pl[1][i].Y);
                line.Add(pl[0][i] - vec / lanenumber * laneindex);
            }
            return line;
        }

        public static PointCollection UpdatePoints(PointCollection pc)
        {
            PointCollection tmp = new PointCollection();
            tmp.Add(pc[0]);
            for (int i = 1; i < pc.Count - 1; i += 2)
            {
                if (Helper.GetIntersection(pc[i - 1], pc[i], pc[i + 1], pc[i + 2]).HasValue)
                {
                    Point p = (Point)Helper.GetIntersection(pc[i - 1], pc[i], pc[i + 1], pc[i + 2]);
                    tmp.Add(p);
                }
                else
                    tmp.Add(pc[i + 1]);
            }
            tmp.Add(pc[pc.Count - 1]);
            return tmp;
        }

        public static void Draw(DrawingContext dc, Brush brush, PointCollection points, Pen pen)
        {
            if (points.Count != 0)
            {
                PathGeometry roadAreaFirstSubgrade = new PathGeometry();
                PolyLineSegment roadAreaFirstSubgradePolyLine = new PolyLineSegment();
                PathFigure roadAreaFirstSubgradePathFigure = new PathFigure() { StartPoint = points[0], IsFilled = true };
                roadAreaFirstSubgradePolyLine.Points = points;
                roadAreaFirstSubgradePathFigure.Segments.Add(roadAreaFirstSubgradePolyLine);
                roadAreaFirstSubgrade.Figures.Add(roadAreaFirstSubgradePathFigure);
                dc.DrawGeometry(brush, pen, roadAreaFirstSubgrade);
            }
        }

        //绘制隔离带
        public static void DrawIsolationBelt(DrawingContext dc, PointCollection points, Point crosspoint, int isoffset = -1)
        {
            Pen pen = Helper.CreatePen((Brush)new BrushConverter().ConvertFromString("#90FFFFFF"), Helper.CreateDashStyle("2,2"), 2);

            List<PointCollection> entry01 = Helper.GetOffsetPoints(points, 1, crosspoint, isoffset);

            foreach (var item in entry01)
            {
                Helper.Draw(dc, Brushes.Transparent, item, pen);
            }

            List<PointCollection> entry0 = Helper.GetOffsetPoints(points, 4, crosspoint, isoffset);

            pen = Helper.CreatePen((Brush)new BrushConverter().ConvertFromString("#90FFA500"), null, 2);
            foreach (var item in entry0)
            {
                Helper.Draw(dc, Brushes.Transparent, item, pen);
            }
        }



        /// <summary>
        /// 计算两条直线的交点
        /// </summary>
        /// <param name="p1">L1的点1坐标</param>
        /// <param name="p2">L1的点2坐标</param>
        /// <param name="p3">L2的点1坐标</param>
        /// <param name="p4">L2的点2坐标</param>
        /// <returns></returns>
        public static Point? GetIntersection(Point p1, Point p2, Point p3, Point p4)
        {
            /*
             * L1，L2都存在斜率的情况：
             * 直线方程L1: ( y - y1 ) / ( y2 - y1 ) = ( x - x1 ) / ( x2 - x1 ) 
             * => y = [ ( y2 - y1 ) / ( x2 - x1 ) ]( x - x1 ) + y1
             * 令 a = ( y2 - y1 ) / ( x2 - x1 )
             * 有 y = a * x - a * x1 + y1   .........1
             * 直线方程L2: ( y - y3 ) / ( y4 - y3 ) = ( x - x3 ) / ( x4 - x3 )
             * 令 b = ( y4 - y3 ) / ( x4 - x3 )
             * 有 y = b * x - b * x3 + y3 ..........2
             * 
             * 如果 a = b，则两直线平等，否则， 联解方程 1,2，得:
             * x = ( a * x1 - b * x3 - y1 + y3 ) / ( a - b )
             * y = a * x - a * x1 + y1
             * 
             * L1存在斜率, L2平行Y轴的情况：
             * x = x3
             * y = a * x3 - a * x1 + y1
             * 
             * L1 平行Y轴，L2存在斜率的情况：
             * x = x1
             * y = b * x - b * x3 + y3
             * 
             * L1与L2都平行Y轴的情况：
             * 如果 x1 = x3，那么L1与L2重合，否则平等
             * 
            */

            double a = 0, b = 0;
            int state = 0;

            if (p1.X != p2.X)
            {
                a = (p2.Y - p1.Y) / (p2.X - p1.X);
                state |= 1;
            }
            if (p3.X != p4.X)
            {
                b = (p4.Y - p3.Y) / (p4.X - p3.X);
                state |= 2;
            }
            switch (state)
            {
                case 0: //L1与L2都平行Y轴
                    {
                        if (p1.X == p3.X)
                        {
                            throw new Exception("两条直线互相重合，且平行于Y轴，无法计算交点。");
                        }
                        else
                        {
                            throw new Exception("两条直线互相平行，且平行于Y轴，无法计算交点。");
                        }
                    }
                case 1: //L1存在斜率, L2平行Y轴
                    {
                        double x = p3.X;
                        double y = a * x - a * p1.X + p1.Y;
                        return new Point(x, y);
                    }
                case 2: //L1 平行Y轴，L2存在斜率
                    {
                        double x = p1.X;
                        double y = b * x - b * p3.X + p3.Y;
                        return new Point(x, y);
                    }
                case 3: //L1，L2都存在斜率
                    {
                        if (a == b)
                        {
                            //throw new Exception("两条直线平行或重合，无法计算交点。");
                            return null;
                        }
                        double x = (a * p1.X - b * p3.X - p1.Y + p3.Y) / (a - b);
                        double y = a * x - a * p1.X + p1.Y;
                        return new Point(x, y);
                    }
            }
            throw new Exception("不可能发生的情况");
        }

    }
}
